import { ResourceDataEntry } from "./ResourceDataEntry.ts";
import { ResourceDirectoryTable } from "./ResourceDirectoryTable.ts";

/**
 * 定义与资源目录相关的常量和成员变量。
 * 该类提供了对资源目录结构的抽象，包括资源的ID、子目录偏移量、资源目录表和资源数据入口。
 * @author tongxin
 * @date 2024/4/20 22:40
 */
export class ResourceDirectoryEntry {
  /**
   * 标识位掩码，用于判断是否是头信息
   */
  static HEADER_MASK = 0x80000000 as const;
  /**
   * 位置掩码，用于提取位置信息
   */
  static LOCATION_MASK = 0x7FFFFFFF as const;
  /**
   * 长度常量，指定每个条目的长度
   */
  static LENGTH = 8 as const;
  /**
   * 资源的整数ID
   */
  integerId?: number;
  /**
   * 子目录的偏移量
   */
  subdirectoryOffset?: number;
  /**
   * 资源目录表
   */
  resourceDirectoryTable?: ResourceDirectoryTable;
  /**
   * 资源数据入口
   */
  resourceDataEntry?: ResourceDataEntry;
  dataReader: IPEFileReader;
  offset: number;
  baseOffset: number;

  /**
   * 构造函数用于初始化ResourceDirectoryEntry实例。
   * @param dataReader 提供数据读取功能的IDataReader对象。
   * @param offset 当前目录项在数据流中的偏移量。
   * @param baseOffset 基础偏移量，用于计算资源数据或子目录的实际位置。
   */
  constructor(dataReader: IPEFileReader, baseOffset: number) {
    this.dataReader = dataReader;
    this.offset = dataReader.getOffset();
    this.baseOffset = baseOffset;

  }

  async read() {
    this.dataReader.setOffset(this.offset)
    const byteArray = await this.dataReader.read(ResourceDirectoryEntry.LENGTH, this.offset);
    // 从读取的字节数组中解析出整数ID和子目录偏移量
    this.integerId = byteArray.readDWord();
    this.subdirectoryOffset = byteArray.readDWord();

    // 判断当前目录项是否为叶子节点
    if (this.isLeaf()) {
      // 如果是叶子节点，则创建一个ResourceDataEntry实例
      this.resourceDataEntry = new ResourceDataEntry(
        await this.dataReader.read(ResourceDataEntry.LENGTH, this.baseOffset + this.subdirectoryOffset)
      );
      return;
    }
    this.dataReader.setOffset(this.baseOffset + this.subdirectoryOffset & ResourceDirectoryEntry.LOCATION_MASK);
    // 如果不是叶子节点，则创建一个ResourceDirectoryTable实例
    this.resourceDirectoryTable = new ResourceDirectoryTable(this.dataReader, this.baseOffset);
    await this.resourceDirectoryTable.read()
  }

  /**
   * 判断当前对象是否为叶子节点。
   * 该方法通过检查subdirectoryOffset与HEADER_MASK的按位与结果是否为0来判断。
   * 如果结果为0，则表示当前节点为叶子节点；否则，表示当前节点不是叶子节点。
   *
   * @return Boolean 返回一个布尔值，如果当前节点是叶子节点，则返回true；否则返回false。
   */
  isLeaf(): boolean {
    return (this.subdirectoryOffset! & ResourceDirectoryEntry.HEADER_MASK) == 0;
  }
}
